/*******************************************************************************
  * @file                   FLASH.c
  * @Author:                MQjehovah                 mail:MQjehovah@hotmail.com
  * @version                1.0.0
  * @date                   2017.11.23
  * @brief                  
  ******************************************************************************
  * @attention
*******************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include "FLASH.h"
#include "delay.h"
#include "USART.h"
/* Definition ----------------------------------------------------------------*/

/* Functions -----------------------------------------------------------------*/
/*******************************************************************************
  * @brief  读取指定地址数据              
  * @param  addr:读地址               
  * @retval 对应数据              
  * @Note   None              
*******************************************************************************/
u32 FLASH_Readu32(u32 addr)
{
	return *(u32 *)addr;
}

/*******************************************************************************
  * @brief  获取某个地址所在的flash扇区        
  * @param  addr:flash地址           
  * @retval 0~11,即addr所在的扇区         
  * @Note   None              
*******************************************************************************/
uint32_t FLASH_GetFlashSector(u32 addr)
{
	if (addr < ADDR_FLASH_SECTOR_1)
		return FLASH_Sector_0;
	else if (addr < ADDR_FLASH_SECTOR_2)
		return FLASH_Sector_1;
	else if (addr < ADDR_FLASH_SECTOR_3)
		return FLASH_Sector_2;
	else if (addr < ADDR_FLASH_SECTOR_4)
		return FLASH_Sector_3;
	else if (addr < ADDR_FLASH_SECTOR_5)
		return FLASH_Sector_4;
	else if (addr < ADDR_FLASH_SECTOR_6)
		return FLASH_Sector_5;
	else if (addr < ADDR_FLASH_SECTOR_7)
		return FLASH_Sector_6;
	else if (addr < ADDR_FLASH_SECTOR_8)
		return FLASH_Sector_7;
	else if (addr < ADDR_FLASH_SECTOR_9)
		return FLASH_Sector_8;
	else if (addr < ADDR_FLASH_SECTOR_10)
		return FLASH_Sector_9;
	else if (addr < ADDR_FLASH_SECTOR_11)
		return FLASH_Sector_10;
	return FLASH_Sector_11;
}

/*******************************************************************************
  * @brief  从指定地址开始写入指定长度的数据        
  * @param  addr:写入地址           
  * @retval None      
  * @Note   因为STM32F4的扇区实在太大,没办法本地保存扇区数据,所以本函数
            写地址如果非0XFF,那么会先擦除整个扇区且不保存扇区数据.所以
            写非0XFF的地址,将导致整个扇区数据丢失.建议写之前确保扇区里
            没有重要数据,最好是整个扇区先擦除了,然后慢慢往后写. 
            该函数对OTP区域也有效!可以用来写OTP区!
            OTP区域地址范围:0X1FFF7800~0X1FFF7A0F
            addr:起始地址(此地址必须为4的倍数!!)
            pBuffer:数据指针
            len:字(32位)数(就是要写入的32位数据的个数.)               
*******************************************************************************/
void FLASH_Write(u32 addr, u32 *pBuffer, u32 len)
{
	FLASH_Status status = FLASH_COMPLETE;
	u32 startaddr = 0;
	u32 endaddr = 0;
	if (addr < STM32_FLASH_BASE || addr % 4)
		return;					 //非法地址
	FLASH_Unlock();				 //解锁
	FLASH_DataCacheCmd(DISABLE); //FLASH擦除期间,必须禁止数据缓存

	startaddr = addr;			//写入的起始地址
	endaddr = addr + len * 4;   //写入的结束地址
	if (startaddr < 0X1FFF0000) //只有主存储区,才需要执行擦除操作!!
	{
		while (startaddr < endaddr) //扫清一切障碍.(对非FFFFFFFF的地方,先擦除)
		{
			if (FLASH_Readu32(startaddr) != 0XFFFFFFFF) //有非0XFFFFFFFF的地方,要擦除这个扇区
			{
				status = FLASH_EraseSector(FLASH_GetFlashSector(startaddr), VoltageRange_3); //VCC=2.7~3.6V之间!!
				if (status != FLASH_COMPLETE)
					break; //发生错误了
			}
			else
				startaddr += 4;
		}
	}
	if (status == FLASH_COMPLETE)
	{
		while (addr < endaddr) //写数据
		{
			if (FLASH_ProgramWord(addr, *pBuffer) != FLASH_COMPLETE) //写入数据
			{
				break; //写入异常
			}
			addr += 4;
			pBuffer++;
		}
	}
	FLASH_DataCacheCmd(ENABLE); //FLASH擦除结束,开启数据缓存
	FLASH_Lock();				//上锁
}

/*******************************************************************************
  * @brief  从指定地址开始读出指定长度的数据      
  * @param  addr:起始地址    
            pBuffer:数据指针 
			len:字(4位)数
  * @retval 0~11,即addr所在的扇区         
  * @Note   None              
*******************************************************************************/
void FLASH_Read(u32 addr, u32 *pBuffer, u32 len)
{
	u32 i;
	for (i = 0; i < len; i++)
	{
		pBuffer[i] = FLASH_Readu32(addr); //读取4个字节.
		addr += 4;						  //偏移4个字节.
	}
}
/*********************************END OF FILE**********************************/
